/* 
 * This program is free software; you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; either version 3 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
 * for more details.
 * 
 * You should have received a copy of the GNU General Public License along 
 * with this program; if not, write to the Free Software Foundation, Inc., 
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#ifndef WISHMASTER_ENTITYCOLLECTOR_H
#define WISHMASTER_ENTITYCOLLECTOR_H

#include "log.h"
#include <vector>
#include <map>
#include <algorithm>

namespace Wishmaster
{
	/*
	 This container stores posts and threads, allowing efficient access to elements.
	 What we need is container that meets following requirements:
	 Appending element - O(N)
	 Access by id - O(log(N)) [Well, O(1) would be nice, but log is ok too]
	 Access by position number - O(1)
	 */
	template <typename T, typename IdType>
	class EntityCollector
	{
	public:
		typedef std::vector<T> TVector;
		typedef std::map<IdType, T> TMap;

		EntityCollector()
		{
		}

		virtual ~EntityCollector()
		{
		}

		void push_back(T obj)
		{
			typename TMap::iterator it = m_map.find(obj->id());
			if(it != m_map.end())
			{
				if(it->second == obj)
					return;

				for(typename TVector::iterator vit = m_vector.begin(); vit != m_vector.end(); ++vit)
				{
					if((*vit)->id() == obj->id())
					{
						m_vector.erase(vit);
						break;
					}
				}
				it->second = obj;
			}
			else
				m_map[obj->id()] = obj;
			m_vector.push_back(obj);
		}

		T lookup(const IdType& id)
		{
			typename TMap::iterator it = m_map.find(id);
			if(it != m_map.end())
				return it->second;
			return T();
		}

		T get(const IdType& id)
		{
			for(typename TVector::iterator vit = m_vector.begin(); vit != m_vector.end(); ++vit)
			{
				if((*vit)->id() == id)
					return (*vit);
			}
			return T();
		}

		T getNth(int n) const
		{
			if(n < 0 || n >= (int)m_vector.size())
				return T();
			return m_vector[n];
		}

		T pick(const IdType& id)
		{
			for(typename TVector::iterator vit = m_vector.begin(); vit != m_vector.end(); ++vit)
			{
				if((*vit)->id() == id)
				{
					T t = *vit;
					m_vector.erase(vit);
					typename TMap::iterator mit = m_map.find(id);
					m_map.erase(mit);
					return t;
				}
			}
			return T();
		}

		int getPosition(const IdType& id)
		{
			int i = 0;
			for(typename TVector::iterator vit = m_vector.begin(); vit != m_vector.end(); ++vit, i++)
			{
				if((*vit)->id() == id)
					return i;
			}
			return -1;
		}

		int count() const
		{
			return m_vector.size();
		}

		void clear()
		{
			m_vector.clear();
			m_map.clear();
		}

		void sort()
		{
			std::sort(m_vector.begin(), m_vector.end(), T::sortFunction);
		}

		typename TVector::iterator begin()
		{
			return m_vector.begin();
		}

		typename TVector::iterator end()
		{
			return m_vector.end();
		}

	private:
		std::vector<T> m_vector;
		std::map<IdType, T> m_map;
	};
}

#endif

